Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Start warning on each use of a deprecated API #21939

Merged
merged 17 commits into from
Jan 18, 2024

Conversation

bartlomieju
Copy link
Member

@bartlomieju bartlomieju commented Jan 14, 2024

This commit introduces deprecation warnings for "Deno.*" APIs.

This is gonna be quite noisy, but should tremendously help with user code updates to ensure
smooth migration to Deno 2.0. The warning is printed at each unique call site to help quickly
identify where code needs to be adjusted. There's some stack frame filtering going on to
remove frames that are not useful to the user and would only cause confusion.

The warning can be silenced using "--quiet" flag or "DENO_NO_DEPRECATION_WARNINGS" env var.

"Deno.run()" API is now using this warning. Other deprecated APIs will start warning
in follow up PRs.

Example:

import { runEcho as runEcho2 } from "http://localhost:4545/run/warn_on_deprecated_api/mod.ts";

const p = Deno.run({
  cmd: [
    Deno.execPath(),
    "eval",
    "console.log('hello world')",
  ],
});
await p.status();
p.close();

async function runEcho() {
  const p = Deno.run({
    cmd: [
      Deno.execPath(),
      "eval",
      "console.log('hello world')",
    ],
  });
  await p.status();
  p.close();
}

await runEcho();
await runEcho();

for (let i = 0; i < 10; i++) {
  await runEcho();
}

await runEcho2();
$ deno run --allow-read foo.js
Warning
├ Use of deprecated "Deno.run()" API.
│
├ This API will be removed in Deno 2.0. Make sure to upgrade to a stable API before then.
│
├ Suggestion: Use "Deno.Command()" API instead.
│
└ Stack trace:
  └─ at file:///Users/ib/dev/deno/foo.js:3:16

hello world
Warning
├ Use of deprecated "Deno.run()" API.
│
├ This API will be removed in Deno 2.0. Make sure to upgrade to a stable API before then.
│
├ Suggestion: Use "Deno.Command()" API instead.
│
└ Stack trace:
  ├─ at runEcho (file:///Users/ib/dev/deno/foo.js:8:18)
  └─ at file:///Users/ib/dev/deno/foo.js:13:7

hello world
Warning
├ Use of deprecated "Deno.run()" API.
│
├ This API will be removed in Deno 2.0. Make sure to upgrade to a stable API before then.
│
├ Suggestion: Use "Deno.Command()" API instead.
│
└ Stack trace:
  ├─ at runEcho (file:///Users/ib/dev/deno/foo.js:8:18)
  └─ at file:///Users/ib/dev/deno/foo.js:14:7

hello world
Warning
├ Use of deprecated "Deno.run()" API.
│
├ This API will be removed in Deno 2.0. Make sure to upgrade to a stable API before then.
│
├ Suggestion: Use "Deno.Command()" API instead.
│
└ Stack trace:
  ├─ at runEcho (file:///Users/ib/dev/deno/foo.js:8:18)
  └─ at file:///Users/ib/dev/deno/foo.js:17:9

hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
Warning
├ Use of deprecated "Deno.run()" API.
│
├ This API will be removed in Deno 2.0. Make sure to upgrade to a stable API before then.
│
├ Suggestion: Use "Deno.Command()" API instead.
│
├ Suggestion: It appears this API is used by a remote dependency.
│             Try upgrading to the latest version of that dependency.
│
└ Stack trace:
  ├─ at runEcho (http://localhost:4545/run/warn_on_deprecated_api/mod.ts:2:18)
  └─ at file:///Users/ib/dev/deno/foo.js:20:7

hello world

Screenshot 2024-01-15 at 17 14 53

Closes #21839

@bartlomieju bartlomieju added this to the 1.40 milestone Jan 14, 2024
@iuioiua
Copy link
Contributor

iuioiua commented Jan 15, 2024

Closes #21839

@bartlomieju
Copy link
Member Author

Note to self: add a test that calls deprecated API in a function and then call that function in a for-loop - verify that warning is only printed once.


function warnOnDeprecatedApi(apiName, stack) {
const stackLines = StringPrototypeSplit(stack, "\n");
ArrayPrototypeShift(stackLines);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious why we shift one item here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to remove the Error\n at the start of the output from new Error().stack.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if that's worth the cost of split, shift, and join

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest stack.slice(6) with a comment.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also suggest we should do that slice at the line of "%cThis API was called from:\n" + stackString + "\n", to minimize the overhead of this util

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also filtering irrelevant stack frames. Without it the stacks are very noisy and make it hard to figure out where the API is called. It's not like this API will be called in the hot path (and if it is it's yet another reason to fix user code quickly :))

Copy link
Member Author

@bartlomieju bartlomieju Jan 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will change the logic to first check if such stack traces was produced before manipulating the stack. Done.

"%cWarning",
"color: yellow; font-weight: bold;",
);
console.log(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When importing from deno_std without a pinned version (e.g. import * as http from "https://deno.land/std/http/server.ts), the warning printed has a yellow "Warning" prefix and unformatted rest-of-text. Should this warning be consistent with that?
image

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I want it to stand out and be sore to the eyes :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea 😆

@iuioiua
Copy link
Contributor

iuioiua commented Jan 15, 2024

Should we also provide the option to mute these warnings by setting a NO_DEPRECATED_WARNINGS=1 in the current process?

@bartlomieju
Copy link
Member Author

Use API from Deno.core that gets the last user stack frame.

@bartlomieju
Copy link
Member Author

Warn on each rid getter in APIs as well.

@bartlomieju
Copy link
Member Author

Waiting on #21961.

Might want to add an env var after all - it might be useful in tests at least for the time being we still have these deprecated APIs.

Copy link
Member

@kt3k kt3k left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Member

@dsherret dsherret left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Nice!

@bartlomieju bartlomieju enabled auto-merge (squash) January 18, 2024 23:11
@bartlomieju bartlomieju merged commit c62615b into denoland:main Jan 18, 2024
14 checks passed
@bartlomieju bartlomieju deleted the warn_on_deprecated_api branch January 18, 2024 23:30
@@ -728,6 +729,10 @@ impl CliOptions {
}
}

let disable_deprecated_api_warning = flags.log_level
== Some(log::Level::Error)
|| std::env::var("DENO_NO_DEPRECATION_WARNINGS").ok().is_some();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC, this accepts DENO_NO_DEPRECATION_WARNINGS=0. Is that deliberate?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noticed this comment - yeah this is deliberate. We don't want to announce and encourage use of this env var - let's consider it for internal testing purposes. We want to "force" users to move away from these APIs.

"color: yellow;",
);
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should print the ability to disable these warnings with the DENO_NO_DEPRECATION_WARNINGS environment variable.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bartlomieju added a commit that referenced this pull request Jan 24, 2024
Follow up to #21939 that adds
deprecation warnings to more `Deno` APIs:

- `Deno.copy()`
- `Deno.iter()`
- `Deno.iterSync()`
- `new Deno.Buffer()`
- `Deno.readAll()`
- `Deno.readAllSync()`
- `Deno.writeAll()`
- `Deno.writeAllSync()`
- `Deno.FsWatcher.return`
- `Deno.serveHttp()`
- `Deno.metrics()`

---------

Signed-off-by: Asher Gomez <ashersaupingomez@gmail.com>
Co-authored-by: Asher Gomez <ashersaupingomez@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

proposal: print deprecation notice when appropriate
4 participants